package edu.bbu.cshu.wmpc.formalization.PascalSource;

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import edu.bbu.cshu.wmpc.core.SourceCodeWmpc;
import edu.bbu.cshu.wmpc.formalization.Formalization;

/**
 * <ul>
 * <li><b><i>ConcratePascalFormalization</i></b></li>
 * <li style="list-style: none;"></li>
 * <li style="list-style: none;">
 * Class that extends {@link Formalization} and implements its methods/functions specific Pascal language
 * 
 * @author WMPC team
 * </li>
 * </ul>
 */
public class ConcratePascalFormalization extends Formalization {
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>ConcratePascalFormalization</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public ConcratePascalFormalization(}{@link SourceCodeWmpc} {@code param)}</p>
	 * <br>	
	 * Constructor that sets the value of {@code source}.
	 * 
	 * @param param - the source code which type is {@code SourceCodeWmpc}
	 * </li>
	 * </ul>
	 */
	public ConcratePascalFormalization(SourceCodeWmpc param) {
		this.source = param;
	}
	
	public void removeComments() {
		ArrayList<String> tmp = source.getOriginal(); //Original source code

		/*regex*/
		Pattern p1 = Pattern.compile("\\{[^\\{\\}]*\\}"); // { xyz }
		Pattern p2 = Pattern.compile("\\{[^\\{\\}]*$"); // { xyz
		Pattern p3 = Pattern.compile("^[^\\{]*\\}"); // xyz } 
		Pattern p4 = Pattern.compile("^[^\\{\\}]*$");// xyz ->without brackets
		String temp; //variable for actually line
		temp = new String();
		Matcher m1, m2, m3, m4; 
		StringBuffer sb;
		int i = 0;

		while (i < tmp.size()) {
			temp = tmp.get(i);
			sb = new StringBuffer(temp.length());
			m1 = p1.matcher(temp);
			while (m1.find()) { //delete the whole comments in a line
				m1.appendReplacement(sb, Matcher.quoteReplacement(""));
			}
			m1.appendTail(sb);

			temp = sb.toString();

			tmp.set(i, temp);
			sb = new StringBuffer(temp.length());
			m2 = p2.matcher(temp);
			int j = i;
			
			if (m2.find()) {  //delete the string after { bracket and find its } pair
				m2.appendReplacement(sb, Matcher.quoteReplacement(""));
				m2.appendTail(sb);
				temp = sb.toString();
				tmp.set(i, temp);
				j++; // i+1 line
				m3 = p3.matcher(tmp.get(j)); //delete the string before } bracket
			
				while (!m3.find()) {
					tmp.set(j, ""); //the whole line is comment => empty line
					j++;
					m3 = p3.matcher(tmp.get(j));
				}
				
				temp = tmp.get(j);
				sb = new StringBuffer(temp.length());
				m3.appendReplacement(sb, Matcher.quoteReplacement("")); 
				m3.appendTail(sb);
				temp = sb.toString();
				i = j;
			}
			
			tmp.set(i, temp);
			m4 = p4.matcher(tmp.get(i));
			
			if (m4.find()) { //if there is no comment we will go to the next line
				tmp.set(i, temp);
				i++;
			}
		}
		source.setModified(tmp); //set the modified sourceCode which is without comments
	}

	public String removeQuates(String str) {
		return str.replaceAll("['].*[']", "");
	}

	public String removeWhitespace(String str) {
		str = str.replaceAll("\\t", "");
		str = str.trim().replaceAll(" +", " ");
		if (str.trim().length() == 0)
			str = "";
		return str;
	}

	public String removeImports(String str) {
			if (str.toUpperCase().indexOf("USES") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("CLRSCR") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("READLN()") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("READKEY;") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("PROGRAM") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("END.") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("TEXTBACKGROUND") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("TEXTCOLOR") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("PROCEDURE") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("FUNCTION") != -1) {
				return "";
			}
			if (str.toUpperCase().indexOf("ELSE") != -1) {
				return "";
			}
		return str;
	}

	public void newLineBreaker() {
		ArrayList<String> tmp = new ArrayList<String>();
		String tempLine = new String(); // a temp line which preserve's a line

		for (int i = 0; i < source.getModified().size(); i++) {
			tempLine = source.getFromModified(i);
			if (tempLine.toUpperCase().indexOf(" PROCEDURE") != -1 || tempLine.toUpperCase().indexOf(" FUNCTION") != -1) { 
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else
			if ((tempLine.indexOf(";") != -1) && tempLine.indexOf("{") == -1
					&& tempLine.indexOf("}") == -1
					&& tempLine.toUpperCase().indexOf(" FOR") == -1
					&& tempLine.toUpperCase().indexOf(" WHILE") == -1
					&& tempLine.toUpperCase().indexOf(" IF") == -1
					&& tempLine.toUpperCase().indexOf(" UNTIL") == -1
					&& tempLine.toUpperCase().indexOf(" THEN") == -1
					&& tempLine.toUpperCase().indexOf(" REPEAT") == -1
					&& tempLine.toUpperCase().indexOf(" UNTIL") == -1) {
				StringTokenizer strToken = new StringTokenizer(tempLine, ";");
				if (tempLine.indexOf(";") == tempLine.lastIndexOf(";")) {
					tmp.add(tempLine);
					source.addKey(tmp.size()-1, i);
				} else {
					while (strToken.hasMoreTokens() == true) {
						tmp.add(strToken.nextToken().toString() + ";");
						source.addKey(tmp.size()-1, i);
					}
				}
			} else if (tempLine.toUpperCase().indexOf("BEGIN") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.toUpperCase().indexOf("END") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0,
						tempLine.toUpperCase().indexOf("BEGIN") + 5, charTemp,
						0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0,
						tempLine.toUpperCase().indexOf("BEGIN") + 5, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.toUpperCase().indexOf("REPEAT") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.toUpperCase().indexOf("END") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0,
						tempLine.toUpperCase().indexOf("REPEAT") + 6, charTemp,
						0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0,
						tempLine.toUpperCase().indexOf("REPEAT") + 6, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.toUpperCase().indexOf("UNTIL") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.toUpperCase().indexOf("END") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0,
						tempLine.toUpperCase().indexOf("UNTIL") + 5, charTemp,
						0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0,
						tempLine.toUpperCase().indexOf("UNTIL") + 5, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.toUpperCase().indexOf("BEGIN") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.toUpperCase().indexOf("END") != -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("begin") + 5, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff
						.replace(0, tempLine.indexOf("begin") + 5, "")
						.toString();
				StringTokenizer strToken = new StringTokenizer(tempLine, ";");
				while (strToken.hasMoreTokens()) {
					String tmpForToken = strToken.nextToken();
					if (tmpForToken.toUpperCase().indexOf("END") == -1) {
						tmp.add(tmpForToken + ";");
						source.addKey(tmp.size()-1, i);
					}
					else {
						tmp.add(tmpForToken + ";");
						source.addKey(tmp.size()-1, i);
					}
				}
			} else if (tempLine.indexOf("END") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.indexOf("BEGIN") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("END") + 1, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf("END") + 1, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.toUpperCase().indexOf("DO") != -1
					&& tempLine.indexOf(";") != -1 && tempLine.length() > 1
					&& tempLine.indexOf("BEGIN") == -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0, tempLine.indexOf("do") + 2, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0, tempLine.indexOf("do") + 2, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else if (tempLine.toUpperCase().indexOf(" THEN") != -1
					&& tempLine.toUpperCase().indexOf(";") != -1) {
				char[] charTemp = new char[tempLine.length()];
				String tempForCopy;
				tempLine.getChars(0,
						tempLine.toUpperCase().indexOf(" THEN") + 4, charTemp, 0);
				tempForCopy = new String(charTemp);
				tmp.add(tempForCopy);
				source.addKey(tmp.size()-1, i);
				StringBuffer strBuff = new StringBuffer(tempLine);
				tempLine = strBuff.replace(0,
						+tempLine.toUpperCase().indexOf(" THEN") + 4, "")
						.toString();
				tmp.add(tempLine);
				source.addKey(tmp.size()-1, i);
			} else {
				tmp.add(tempLine.toString());
				source.addKey(tmp.size()-1, i);
			}
		}
		source.setModified(tmp);
	}

	public String removeOutput(String str) {
		if (str.toUpperCase().indexOf(" WRITE(") != -1 || str.toUpperCase().indexOf(" WRITELN(") != -1){
			return "";
		} else {
			return str;
		}
	}

	public String removeTryCatch(String str) {
		return str;
	}

	public String removeBeginEnd(String str) {
		String temp = str;
		
		if (temp.toUpperCase().indexOf("BEGIN") != -1) {
			return "";
		} else {
			if (temp.toUpperCase().indexOf("END") != -1) {
				return "";
			} else {
				return str;
			}
			
		}		
	}

	public String removeInput(String str) {
		if (str.toUpperCase().indexOf(" READ(") != -1 || str.toUpperCase().indexOf("READLN") != -1){
			return "";
		} else {
			return str;
		}
	}

	public String handleVariables(String str) {
		if (str.matches("^#*[ ][A-Za-z0-9]*\\.{1}[A-Za-z0-9]*[ ]#*$")) {
			return str;
		}
		String tmp = new String(str);
	
		//declaration
		tmp = tmp.replaceAll("var", "");
		if (tmp.matches("[ ]*[A-Za-z0-9,\\(\\) ]*[ ]*[:]{1}[ ]*[A-Za-z0-9;]*")) {
			tmp = tmp.substring(0,tmp.indexOf(":")) + ";";
			StringTokenizer st = new StringTokenizer(tmp,",");
			tmp = "";
			while (st.hasMoreTokens() == true) {
				st.nextToken();
				tmp = tmp + "var,";
			}
			tmp = tmp.substring(0, tmp.length()-1);
			tmp = tmp + ";";
		}
		
		// := assignments
		if (tmp.matches("[ ]*[A-Za-z0-9,\\[\\]]*[ ]*:=[ ]*[A-Za-z0-9,\\[\\]\\-;]*")) {
			tmp = "var:=var;";
		}
		if (tmp.toLowerCase().indexOf("for ") != -1 && tmp.toLowerCase().indexOf("to") != -1 && tmp.toLowerCase().indexOf(":=") != -1) {
			tmp = "for var:=var to var do";
		}
		if (tmp.toLowerCase().indexOf("for") != -1 && tmp.toLowerCase().indexOf("downto") != -1) {
			tmp = "for var:=var downto var do";
		}
		if (tmp.toLowerCase().indexOf("inc") != -1 && tmp.indexOf("(") != -1 && tmp.indexOf(")") != -1 && tmp.indexOf(";") != -1) {
			tmp = "inc(var);";
		}
		if (tmp.toLowerCase().indexOf("dec") != -1 && tmp.indexOf("(") != -1 && tmp.indexOf(")") != -1 && tmp.indexOf(";") != -1) {
			tmp = "dec(var)";
		}
		
		if (tmp.indexOf("+") != -1 || tmp.indexOf("-") != -1
				|| tmp.indexOf("/") != -1 || tmp.indexOf("*") != -1
						|| tmp.indexOf("mod") != -1 || tmp.indexOf("div") != -1) {
			String replacement = tmp.replaceAll(
					"[ ]?[A-Za-z0-9\\[\\]<>]+ [A-Za-z0-9]+[ ]?", "var");
			replacement = replacement.replaceAll(
					"[ ]?[A-Za-z0-9\\.\\(\\)\\[\\]\"\']+[ ]?", "var");
			return replacement;
		}
		if (tmp.toUpperCase().indexOf("WHILE ") != -1 || tmp.toUpperCase().indexOf("UNTIL ") != -1 || tmp.toUpperCase().indexOf("IF ") != -1 || tmp.toUpperCase().indexOf("SWITCH ") != -1 || tmp.toUpperCase().indexOf("CASE ") != -1 ) {
			
			str = str.replaceAll("\\(|\\)", "");
			tmp = "";
			int index = 0;

			if ((index = str.indexOf("if")) != -1) {
				tmp = str.substring(0, index + 2) + " ";
				str = str.substring(index + 3, str.length());
			} else if ((index = str.indexOf("while")) != -1) {
				tmp = str.substring(0, index + 5) + " ";
				str = str.substring(index + 6, str.length());
			} else if ((index = str.indexOf("switch")) != -1) {
				tmp = str.substring(0, index + 6) + " ";
				str = str.substring(index + 7, str.length());
			} else if ((index = str.indexOf("case")) != -1) {
				tmp = str.substring(0, index + 4) + " ";
				str = str.substring(index + 5, str.length());
			}else if ((index = str.indexOf("until")) != -1) {
				tmp = str.substring(0, index + 5) + " ";
				str = str.substring(index + 6, str.length());
			}
			String replacement = str.replaceAll(
					"[ ]?[A-Za-z0-9\\[\\]<> ]+ [A-Za-z0-9]+[ ]?", "var");
			replacement = replacement.replaceAll(
					"[ ]?[A-Za-z0-9\\.\\(\\)\\[\\]\"\']+[ ]?", "var");

			return tmp + replacement;
		}
		return tmp;
	}

	protected String shortenVariables(String str) {
		return str.replaceAll("([\\W]?)([\\w]{4})([\\w]*)([\\W]?)", "$1$2$4");
	}
}
